package main

import (
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
	"net/http"
	"reflect"
)

type User struct {
	Name  string `json:"name" binding:"required,min=4,max=12"`       // 用户名
	Age   int    `json:"age" binding:"gte=18,lte=60"`                // 年龄
	Pwd   string `json:"pwd" binding:"required,eqfield=RePwd,min=8"` // 密码
	RePwd string `json:"rePwd"`                                      //重复密码
}

type Student struct {
	Name     string   `json:"name" binding:"contains=l,startswith=ta,endswith=on,excludes=p"`
	Age      int      `json:"age"`
	Sex      string   `json:"sex" binding:"oneof=man woman"` // 性别
	LikeList []string `json:"likeList" binding:"required,dive,startswith=like"`
	IP       string   `json:"ip" binding:"ip"`
	Url      string   `json:"url" binding:"url"`
	Uri      string   `json:"uri" binding:"uri"`
	Date     string   `json:"date" binding:"datetime=2006-01-02 15:04:05"`
}

type User2 struct {
	Name string `json:"name" binding:"required" msg:"请输入用户名"` // 用户名
	Age  int    `json:"age" binding:"required" msg:"请输入年龄"`   // 年龄
}

type User3 struct {
	Name string `json:"name" binding:"required,sign"`
	Age  int    `json:"age" binding:"required"`
}

func main() {
	router := gin.Default()
	// 注意一定是转成指针
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		v.RegisterValidation("sign", SignUpValid)
	}
	router.POST("/", func(c *gin.Context) {
		var user User
		err := c.ShouldBindJSON(&user)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{"msg": err.Error(), "data": nil})
			return
		}

		c.JSON(http.StatusOK, gin.H{"msg": "success", "data": user})
	})
	router.POST("/inner", func(c *gin.Context) {
		var student Student
		err := c.ShouldBindJSON(&student)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{"msg": err.Error(), "data": nil})
			return
		}

		c.JSON(http.StatusOK, gin.H{"msg": "success", "data": student})
	})
	router.POST("/custom", func(c *gin.Context) {
		var user User2
		err := c.ShouldBindJSON(&user)
		if err != nil {
			// 将err接口短线为具体类型
			c.JSON(200, gin.H{"msg": getErrMsg(err, &user)})
			return
		}
		c.JSON(200, gin.H{"msg": "success"})
	})
	router.POST("/customValid", func(c *gin.Context) {
		var user User3
		err := c.ShouldBindJSON(&user)
		if err != nil {
			// 将err接口短线为具体类型
			c.JSON(200, gin.H{"msg": err.Error()})
			return
		}
		c.JSON(200, gin.H{"msg": "success"})
	})
	router.Run(":8080")
}

func SignUpValid(fl validator.FieldLevel) bool {
	nameList := []string{"a", "b", "c"}
	name := fl.Field().Interface().(string)
	for _, n := range nameList {
		if name == n {
			return false
		}
	}
	return true
}

func getErrMsg(err error, obj interface{}) string {
	rType := reflect.TypeOf(obj)
	if errs, ok := err.(validator.ValidationErrors); ok {
		// 断言成功
		for _, e := range errs {
			// 循环每一个报错
			// 根据报错的字段名，获取结构体的具体字段
			if f, exists := rType.Elem().FieldByName(e.Field()); exists {
				return f.Tag.Get("msg")
			}
		}
	}
	return err.Error()
}
